package com.zzt.pagehelp.util

import kotlinx.coroutines.flow.MutableStateFlow

/**
 * @author: zeting
 * @date: 2022/10/26
 *
 */
class Pager<T>(
    internal val pageConfig: PageConfig,
    internal val request: suspend (Int, Int) -> List<T>
) {
    internal val pageState: PageState<T> = PageState()

    /**
     * 设置是否没有更多数据的状态监听器
     */
    fun setNoMoreStateListener(noMoreStateState: PageState.NoMoreStateListener) {
        pageState.setNoMoreStateListener(noMoreStateListener = noMoreStateState)
    }

    /**
     * 添加加载状态监听器
     */
    fun addLoadStateListener(loadStateState: PageState.LoadStateListener) {
        pageState.addLoadStateListener(loadStateListener = loadStateState)
    }

    /**
     * 发送没有更多数据的状态
     *
     * 如果外部需要调用此方法，请使用[PageHelper.callNoMoreState]
     */
    internal fun callNoMoreState(noMoreState: Boolean) {
        pageState._noMoreStateListener?.noMoreState(noMoreState = noMoreState)
    }

    /**
     * 刷新（重新获取第一页）
     */
    internal suspend fun refresh(): List<T> {
        pageState.callLoadState(loadState = LoadState.Loading)
        pageConfig.reset()
        val result = request.runCatching { invoke(pageConfig.index.run { pageConfig.index++ }, pageConfig.size) }
        return checkResult(result = result)
    }

    /**
     * 获取下一页
     */
    internal suspend fun requestNext(): List<T> {
        pageState.callLoadState(loadState = LoadState.Loading)
        val result = request.runCatching { invoke(pageConfig.nextIndex.run { pageConfig.index++ }, pageConfig.size) }
        return checkResult(result = result)
    }

    /**
     * 查验请求的结果
     */
    private fun checkResult(result: Result<List<T>>): List<T> {
        val list = if (result.isSuccess) {
            val _list = result.getOrNull() ?: emptyList()
            pageState.checkPageList(_list, pageConfig.size)
            pageState.callLoadState(loadState = LoadState.NotLoading(pageState.noMore))
            _list
        } else {
            pageConfig.index--  //因为之前在请求数据时，取了页码值后立即对页码进行了+1，因此如果请求数据失败，则需要通过-1将页码进行回退
            val throwable = result.exceptionOrNull() ?: Throwable("获取数据失败")
            pageState.callLoadState(loadState = LoadState.Error(throwable))
            throwable.printStackTrace()
            emptyList()
        }
        return list
    }
}

/**
 * 基础配置
 *
 * @property initIndex  首页页码
 */
class PageConfig(private val initIndex: Int, initSize: Int = 20) {
    var index: Int = initIndex
    var size: Int = initSize

    //上一页页码
    val prevIndex: Int? get() = if (index > initIndex) index - 1 else null

    //下一页页码
    val nextIndex: Int get() = index + 1

    /**
     * 重置数据
     */
    fun reset() {
        index = initIndex
    }
}

/**
 * 所有的状态管理器
 */
class PageState<T> {
    //是否没有更多数据的状态
    val noMoreFlow = MutableStateFlow(false)

    val noMore: Boolean get() = noMoreFlow.value

    /**
     * 检查获取到的数据
     *
     * 计算出是否还有下一页
     */
    fun checkPageList(list: List<T>, pageSize: Int) {
        val _noMore = list.size < pageSize
        if (noMoreFlow.value != _noMore) {
            noMoreFlow.value = _noMore
        }
    }

    /*---------- 是否没有更多数据的状态 ----------*/

    private var noMoreStateListener: NoMoreStateListener? = null

    val _noMoreStateListener: NoMoreStateListener? get() = noMoreStateListener

    fun setNoMoreStateListener(noMoreStateListener: NoMoreStateListener) {
        this.noMoreStateListener = noMoreStateListener
    }

    /**
     * 是否没有更多数据的状态的回调接口
     */
    interface NoMoreStateListener {
        fun noMoreState(noMoreState: Boolean)
    }

    /*---------- 加载状态 ----------*/

    private val loadStateListeners = mutableSetOf<LoadStateListener>()

    fun addLoadStateListener(loadStateListener: LoadStateListener) {
        loadStateListeners.add(loadStateListener)
    }

    fun removeLoadStateListener(loadStateListener: LoadStateListener) {
        loadStateListeners.remove(loadStateListener)
    }

    /**
     * 发送加载状态
     *
     * @param loadState 新的状态
     */
    fun callLoadState(loadState: LoadState) {
        loadStateListeners.forEach {
            it.updateState(loadState = loadState)
        }
    }

    /**
     * 加载状态回调接口
     */
    interface LoadStateListener {
        fun updateState(loadState: LoadState)
    }
}